use serde::{Deserialize, Serialize};

pub mod blackboard;

#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum Value {
    I32(i32),
    I64(i64),
    F32(f32),
    F64(f64),
    Bool(bool),
    String(String),
    Array(Vec<Value>),
    Object(Object),
    Enum(Enum),
    Node,
}

impl Value {
    pub fn get_all_base_types() -> Vec<Value> {
        vec![Value::I32(0), Value::I64(0), Value::F32(0.0), Value::F64(0.0), Value::Bool(false), Value::String("".to_string())]
    }

    #[allow(dead_code)]
    pub fn all_base_types_string() -> Vec<String> {
        Self::get_all_base_types().iter().map(|v| v.get_type_string()).collect()
    }

    pub fn get_type_string(&self) -> String {
        match self {
            Value::I32(_) => "i32".to_string(),
            Value::I64(_) => "i64".to_string(),
            Value::F32(_) => "f32".to_string(),
            Value::F64(_) => "f64".to_string(),
            Value::Bool(_) => "bool".to_string(),
            Value::String(_) => "string".to_string(),
            Value::Array(_) => "array".to_string(),
            Value::Object(_) => "object".to_string(),
            Value::Enum(_) => "enum".to_string(),
            Value::Node => "node".to_string(),
        }
    }

    #[allow(dead_code)]
    pub fn from_type(ty: &str) -> Value {
        match ty.to_lowercase().as_str() {
            "i32" => Value::I32(0),
            "i64" => Value::I64(0),
            "f32" => Value::F32(0.0),
            "f64" => Value::F64(0.0),
            "bool" => Value::Bool(false),
            "string" => Value::String("".to_string()),
            "array" => Value::Array(vec![]),
            "object" => Value::Object(Object {
                ty: "unknown".to_string(),
                fields: vec![],
            }),
            "enum" => Value::Enum(Enum {
                ty: "unknown".to_string(),
                values: vec![],
                selected: "".to_string(),
            }),
            "node" => Value::Node,
            _ => Value::String("".to_string()),
        }
    }
}

impl Value {
    pub fn is_same_type(&self, other: &Value)->bool {
        // std::mem::discriminant(self) == std::mem::discriminant(other)
        match (self, other) {
            (Value::I32(_), Value::I32(_)) => true,
            (Value::I64(_), Value::I64(_)) => true,
            (Value::F32(_), Value::F32(_)) => true,
            (Value::F64(_), Value::F64(_)) => true,
            (Value::Bool(_), Value::Bool(_)) => true,
            (Value::String(_), Value::String(_)) => true,
            (Value::Array(_), Value::Array(_)) => true,
            (Value::Object(obj1), Value::Object(obj2)) => {
                obj1.ty == obj2.ty
            },
            (Value::Enum(e1), Value::Enum(e2)) => {
                e1.ty == e2.ty
            },
            (Value::Node, Value::Node) => true,
            _ => false,
        }
    }

    pub fn value_color(&self) -> [u8; 4] {
        match self {
            Value::I32(_) => [255, 165, 0, 255],        // 橙色
            Value::I64(_) => [255, 140, 0, 255],        // 深橙色
            Value::F32(_) => [255, 215, 0, 255],        // 金色
            Value::F64(_) => [218, 165, 32, 255],       // 金麒麟色
            Value::Bool(_) => [255, 0, 128, 255],       // 品红色
            Value::String(_) => [0, 128, 255, 255],     // 蓝色
            Value::Array(_) => [128, 255, 0, 255],      // 黄绿色
            Value::Object(_) => [255, 0, 255, 255],     // 紫色
            Value::Enum(_) => [0, 255, 128, 255],       // 青色
            Value::Node => [128, 0, 255, 255],          // 靛色
        }
    }
    
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Object {
    pub ty: String,
    pub fields: Vec<(String, Value)>,
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Enum {
    pub ty: String,
    pub values: Vec<String>,
    pub selected: String,
}
